import javax.swing.*;
import javax.swing.plaf.basic.BasicTreeUI;
import java.awt.*;
import java.awt.event.*;
import java.text.DecimalFormat;

import static java.lang.Math.*;

public class Calculator {
    private JFrame frame;
    private JPanel display;
    private JTextField pastLine;
    private JTextField currentLine;

    private String currentNumber;
    private String lastOperator;
    private double result;

    public Calculator() {
        frame = new JFrame("Calculator");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setMinimumSize(new Dimension(350,400));

        GridBagConstraints gbc=new GridBagConstraints();
        gbc.insets=new Insets(4,4,4,4);
        gbc.gridx=0;gbc.gridy=0;
        gbc.weightx=1;gbc.weighty=2.5;gbc.fill=GridBagConstraints.BOTH;gbc.gridheight=1;gbc.gridwidth=4;
        frame.setLayout(new GridBagLayout());

        display = new JPanel(new BorderLayout());
        pastLine=new JTextField();
        pastLine.setEditable(false);
        currentLine=new JTextField();
        currentLine.setEditable(false);
        pastLine.setHorizontalAlignment(SwingConstants.RIGHT);
        currentLine.setHorizontalAlignment(SwingConstants.RIGHT);
        pastLine.setFocusable(false);
        currentLine.setFocusable(false);

        currentLine.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                int fontSize = min((int) (currentLine.getHeight() * 0.6),60); // 调整字体大小的比例可以根据需要进行调整
                Font font = currentLine.getFont().deriveFont((float) fontSize);
                currentLine.setFont(font);
                font = pastLine.getFont().deriveFont((float) (fontSize*0.7));
                pastLine.setFont(font);
            }
        });

        display.add(pastLine,BorderLayout.NORTH);
        display.add(currentLine,BorderLayout.CENTER);
        display.setFocusable(false);

        frame.getContentPane().add(display,gbc);
        gbc.gridwidth=1;
        gbc.weighty=1;
        gbc.gridy=1;

        Container mainContainer=frame.getContentPane();

        addButton(mainContainer, "%", gbc);
        addButton(mainContainer, "CE", gbc);
        addButton(mainContainer, "C", gbc);
        addButton(mainContainer, "DEL", gbc);
        addButton(mainContainer, "1/x", gbc);
        addButton(mainContainer, "x^2", gbc);
        addButton(mainContainer, "sqrt", gbc);
        addButton(mainContainer, "/", gbc);

        addButton(mainContainer, "7", gbc);
        addButton(mainContainer, "8", gbc);
        addButton(mainContainer, "9", gbc);
        addButton(mainContainer, "*", gbc);
        addButton(mainContainer, "4", gbc);
        addButton(mainContainer, "5", gbc);
        addButton(mainContainer, "6", gbc);
        addButton(mainContainer, "-", gbc);
        addButton(mainContainer, "1", gbc);
        addButton(mainContainer, "2", gbc);
        addButton(mainContainer, "3", gbc);
        addButton(mainContainer, "+", gbc);
        addButton(mainContainer, "+/-", gbc);
        addButton(mainContainer, "0", gbc);
        addButton(mainContainer, ".", gbc);
        addButton(mainContainer, "=", gbc);

        frame.addKeyListener(new KeyAdapter() {
            Component[] components=mainContainer.getComponents();
            @Override
            public void keyTyped(KeyEvent e) {
                char keychar=e.getKeyChar();
                System.out.println(keychar);
                switch (keychar){
                    case '0':
                        ((JButton) components[22]).doClick();
                        break;
                    case '1':
                        ((JButton) components[17]).doClick();
                        break;
                    case '2':
                        ((JButton) components[18]).doClick();
                        break;
                    case '3':
                        ((JButton) components[19]).doClick();
                        break;
                    case '4':
                        ((JButton) components[13]).doClick();
                        break;
                    case '5':
                        ((JButton) components[14]).doClick();
                        break;
                    case '6':
                        ((JButton) components[15]).doClick();
                        break;
                    case '7':
                        ((JButton) components[9]).doClick();
                        break;
                    case '8':
                        ((JButton) components[10]).doClick();
                        break;
                    case '9':
                        ((JButton) components[11]).doClick();
                        break;
                    case '+':
                        ((JButton) components[20]).doClick();
                        break;
                    case '-':
                        ((JButton) components[16]).doClick();
                        break;
                    case '*':
                        ((JButton) components[12]).doClick();
                        break;
                    case '/':
                        ((JButton) components[8]).doClick();
                        break;
                    case '\b':
                        ((JButton) components[4]).doClick();
                        break;
                    case '\n':
                    case '=':
                        ((JButton) components[24]).doClick();
                        break;
                    case '.':
                        ((JButton) components[23]).doClick();
                        break;
                }
            }
        });
        frame.setFocusable(true);

        frame.pack();
        frame.setVisible(true);

        currentNumber = "";
        lastOperator = "";
        result = 0;
    }

    private void addButton(Container container, String text, GridBagConstraints c) {
        JButton button = new JButton(text);
        //Font font = new Font("Arial", Font.BOLD, 20);
        //button.setFont(font);
        button.setFocusable(false);
        container.add(button,c);
        button.addActionListener(new ButtonClickListener());
        button.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                int fontSize = min((int) (button.getHeight() * 0.5),35); // 调整字体大小的比例可以根据需要进行调整
                Font font = button.getFont().deriveFont((float) fontSize);
                button.setFont(font);
            }
        });
        c.gridx++;
        if(c.gridx>=4){
            c.gridx=0;
            c.gridy++;
        }
    }

    private class ButtonClickListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            String buttonValue = e.getActionCommand();

            if (buttonValue.matches("[0-9.]")) {
                currentNumber += buttonValue;
            } else if (buttonValue.matches("[+\\-*/%]")) {
                if (!currentNumber.isEmpty()) {
                    calculate();
                    DecimalFormat df = new DecimalFormat("#.################");
                    pastLine.setText(df.format(result)+buttonValue);
                    lastOperator = buttonValue;
                    currentNumber = "";
                }
            } else if (buttonValue.equals("=")) {
                DecimalFormat df = new DecimalFormat("#.################");
                calculate();
                lastOperator = "";
                pastLine.setText("");
                currentNumber = df.format(result);
            } else if (buttonValue.equals("C")) {
                currentNumber = "";
                lastOperator = "";
                result = 0;
                pastLine.setText("");
            } else if (buttonValue.equals("CE")) {
                currentNumber = "";
            } else if (buttonValue.equals("DEL")) {
                if(!currentNumber.isBlank()) currentNumber=currentNumber.substring(0,currentNumber.length()-1);
            } else if (buttonValue.equals("+/-")) {
                if(currentNumber.charAt(0)=='-'){
                    currentNumber=currentNumber.substring(1,currentNumber.length());
                }else{
                    currentNumber="-"+currentNumber;
                }
            } else if (buttonValue.equals("1/x")) {
                double number;
                try{
                    number = Double.parseDouble(currentNumber);
                }catch (NumberFormatException er){
                    return;
                }
                DecimalFormat df = new DecimalFormat("#.################");
                currentNumber=df.format(1/number);
            } else if (buttonValue.equals("sqrt")) {
                double number;
                try{
                    number = Double.parseDouble(currentNumber);
                }catch (NumberFormatException er){
                    return;
                }
                DecimalFormat df = new DecimalFormat("#.################");
                currentNumber=df.format(sqrt(number));
            } else if (buttonValue.equals("x^2")) {
                double number;
                try{
                    number = Double.parseDouble(currentNumber);
                }catch (NumberFormatException er){
                    return;
                }
                DecimalFormat df = new DecimalFormat("#.################");
                currentNumber=df.format(number*number);
            }
            currentLine.setText(currentNumber);
        }

        private boolean calculate() {
            double number;
            try{
                number = Double.parseDouble(currentNumber);
            }catch (NumberFormatException e){
                return false;
            }
            switch (lastOperator){
                case "+":
                    result += number;
                    break;
                case "-":
                    result -= number;
                    break;
                case "*":
                    result *= number;
                    break;
                case "/":
                    result /= number;
                    break;
                case "%":
                    result %= number;
                    break;
                case "":
                    result = number;
                    break;
            }

            return true;
        }
    }


}